﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.HomeServer.Common.Client;
using log4net;

namespace RouterControl.Diag
{
    internal partial class DiagList : UserControl
    {

        #region structs

        public enum DiagResult
        {
            Successful,
            Failed,
            FailedCritical
        }

        public class DiagnosisDoneEventArgs : EventArgs
        {
            public DiagResult Result
            {
                get;
                private set;
            }

            public DiagnosisDoneEventArgs(DiagResult result)
            {
                this.Result = result;
            }
        }

        #endregion

        private readonly ILog _log = LogManager.GetLogger(typeof(DiagList));
        private List<Diagnosis> _diags = new List<Diagnosis>();
        public event EventHandler<DiagnosisDoneEventArgs> OnDiagnosisDone;
        private int _currentProgress;
        private int _totalProgressWeight;

        public DiagList()
        {
            InitializeComponent();

            // add images
            this.imageListDiag.Images.Add(CommonImages.OfflineIcon);
            this.imageListDiag.Images.Add(CommonImages.TaskFailure16);
            this.imageListDiag.Images.Add(CommonImages.TaskWarning16);
            this.imageListDiag.Images.Add(CommonImages.TaskSuccess16);
            this.imageListDiag.Images.Add(CommonImages.GreenIcon);
        }

        public void AddDiagnosis(Diagnosis diag)
        {
            if (diag == null)
	            throw new ArgumentNullException("diag");

            _diags.Add(diag);

            this.listViewDiag.Items.Add(diag.ListItem);
        }

        public void RunDiagnosisAsync()
        {
            // reset
            this.filledBar.Percentage = 0;

            foreach (var d in _diags)
            {
                d.ListItem.ImageIndex = 0;
            }

            // start
            this.diagBgWorker.RunWorkerAsync();
        }

        private void diagBgWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            // prepare
            _currentProgress = 0;
            _totalProgressWeight = (
                from d in _diags
                select d.ProgressWeight
                ).Sum();


            // run diagnostics
            bool abort = false;
            bool failed = false;

            foreach (var d in _diags)
            {
                try
                {
                    // prepare
                    _log.Info("Running diagnosis: " + d.ListItem.Text);

                    d.ListItem.EnsureVisible();
                    d.ListItem.ImageIndex = 4;

                    // run
                    switch (d.Run())
                    {
                        case Diagnosis.DiagResult.Success:
                            _log.Info("Diagnosis succeeded: " + d.ListItem.Text);

                            d.ListItem.ImageIndex = 3;

                            break;

                        case Diagnosis.DiagResult.Failure:
                            _log.Error("Diagnosis failed: " + d.ListItem.Text);

                            d.ListItem.ImageIndex = 2;
                            failed = true;

                            break;

                        case Diagnosis.DiagResult.Abort:
                            _log.Error("Diagnosis failed (abort): " + d.ListItem.Text);

                            d.ListItem.ImageIndex = 1;
                            abort = true;

                            break;
                    }

                    // add diagnosis files
                    FilesToZip.Instance.AddFiles(d.DiagnosticFiles);
                }
                catch (Exception x)
                {
                    _log.Fatal("Diagnosis failed unexpectedly: " + d.ListItem.Text, x);

                    d.ListItem.ImageIndex = 1;
                }
                finally
                {
                    _currentProgress += d.ProgressWeight;

                    this.diagBgWorker.ReportProgress((_currentProgress * 100) / _totalProgressWeight);
                }

                // abort?
                if (abort)
                    break;
            }

            // finalize
            if (abort)
                e.Result = DiagResult.FailedCritical;
            else if (failed)
                e.Result = DiagResult.Failed;
            else
                e.Result = DiagResult.Successful;
        }

        private void diagBgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            this.filledBar.Percentage = e.ProgressPercentage;
        }

        private void diagBgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            this.filledBar.Percentage = 100;
            
            if (this.OnDiagnosisDone != null)
            {
                this.OnDiagnosisDone(this, new DiagnosisDoneEventArgs((DiagResult)e.Result));
            }
        }

        public void ClearAllDiagnosises()
        {
            _diags.Clear();

            this.listViewDiag.Items.Clear();
        }
    }
}
